package cn.icybear.orzjisp.orzvm;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

import cn.icybear.orzjisp.ClosureTable;
import cn.icybear.orzjisp.Constant;
import cn.icybear.orzjisp.Identifier;
import cn.icybear.orzjisp.bytefile.DefualtSection;
import cn.icybear.orzjisp.bytefile.OrzConstants;
import cn.icybear.orzjisp.bytefile.Section;

public class OrzLoader implements OrzConstants {
	public Constant[] constantTable;
	public Section[] sections;
	public int initSectionIndex;
	public void load(byte[] buf) throws IOException, OrzLoaderException{
		load(new ByteArrayInputStream(buf));
	}
	public void load(InputStream in) throws IOException, OrzLoaderException {
		DataInputStream is = new DataInputStream(new BufferedInputStream(in));
		readMagic(is);
		readVersion(is);
		initSectionIndex = is.readUnsignedShort();
		int secCount = is.readUnsignedShort();
//		System.out.println("Section Count:"+secCount);
		sections = new DefualtSection[secCount];
		for (int i = 0; i < secCount; i++) {
			sections[i] = DefualtSection.readSection(is);
			switch (sections[i].getTag()) {
			case TAG_CONSTANT:
				parseConstant((DefualtSection) sections[i]);
				break;
			case TAG_CODE:
				break;
			default:
				throw new OrzLoaderException("Unknown section tag:"
						+ sections[i].getTag());
			}
		}
	}

	public void parseConstant(DefualtSection sect) throws IOException,
			OrzLoaderException {
		DataInputStream is = sect.getInputStream();
		int len = is.readUnsignedShort();
		if (constantTable == null)
			constantTable = new Constant[len+1];//0 for null
		else {
			throw new OrzLoaderException("duplicated constant table");
		}
		constantTable[0] = Constant.OBJ_NULL;
		for (int i = 1; i < len; i++) {
			int tag = is.readUnsignedByte();
			switch (tag) {
			case TAG_INTEGER:
				constantTable[i] = Constant.getConstant(is.readInt());
				break;
			case TAG_DOUBLE:
				constantTable[i] = Constant.getConstant(is.readDouble());
				break;
			case TAG_STRING:
				constantTable[i] = Constant.getConstant(is.readUTF());
				break;
			case TAG_IDENTIFIER:
				constantTable[i] = new Identifier(is.readUTF());
				break;
			case TAG_CLOSERTABLE:
				constantTable[i] = new ClosureTable(is);
				break;
			default:
				throw new OrzLoaderException("Unknow constant tag:" + tag);
			}
		}
	}

	public void readVersion(DataInputStream is) throws IOException,
			OrzLoaderException {
		int ver = is.readInt();
		if (ver>ORZ_VERSION)
			throw new OrzLoaderException("Unsupported Orz Version");
	}

	public void readMagic(DataInputStream in) throws IOException,
			OrzLoaderException {
		int magic = in.readInt();
		if (magic != ORZ_MAGIC)
			throw new OrzLoaderException("Encountered illegal Magic Number");
	}
}
